package org.groupg.project.processManager;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class ApplicationProcessManager {
    private static final Map<String, ProcessInfo> managedProcesses = new ConcurrentHashMap<>();

    // 启动进程
    public ProcessInfo startProcess(String processName, String[] command, File workingDir)
            throws IOException {

        ProcessBuilder processBuilder = new ProcessBuilder(command);
        if (workingDir != null) {
            processBuilder.directory(workingDir);
        }

        // 重定向错误流到输出流
        processBuilder.redirectErrorStream(true);

        Process process = processBuilder.start();
        long pid = getProcessId(process);

        ProcessInfo info = new ProcessInfo();
        info.setName(processName);
        info.setPid(pid);
        info.setStatus(ProcessStatus.RUNNING);
        info.setCommand(String.join(" ", command));
        info.setStartTime(System.currentTimeMillis());

        managedProcesses.put(processName, info);

        // 启动输出监控线程
        startOutputMonitoring(process, processName);

        // 启动进程状态监控
        startProcessMonitoring(process, processName);

        return info;
    }

    // 启动Tomcat特定方法
    public ProcessInfo startTomcat(String tomcatHome) throws IOException {
        String[] command;
        File workingDir = new File(tomcatHome, "bin");

        if (isWindows()) {
            command = new String[]{"cmd.exe", "/c", "startup.bat"};
        } else {
            command = new String[]{"sh", "startup.sh"};
        }

        return startProcess("tomcat", command, workingDir);
    }

    // 停止进程
    public boolean stopProcess(String processName) {
        ProcessInfo info = managedProcesses.get(processName);
        if (info == null) {
            return false;
        }

        try {
            // 先尝试优雅停止
            if (isWindows()) {
                Runtime.getRuntime().exec("taskkill /PID " + info.getPid());
            } else {
                Runtime.getRuntime().exec("kill -15 " + info.getPid());
            }

            // 等待进程结束
            return waitForProcessTermination(processName, 30);
        } catch (Exception e) {
            // 优雅停止失败，强制终止
            return forceStopProcess(processName);
        }
    }

    // 停止Tomcat特定方法
    public boolean stopTomcat(String tomcatHome) throws IOException {
        // 先尝试使用Tomcat的关闭脚本
        File workingDir = new File(tomcatHome, "bin");
        String[] command;

        if (isWindows()) {
            command = new String[]{"cmd.exe", "/c", "shutdown.bat"};
        } else {
            command = new String[]{"sh", "shutdown.sh"};
        }

        ProcessBuilder processBuilder = new ProcessBuilder(command);
        processBuilder.directory(workingDir);
        Process process = processBuilder.start();

        try {
            boolean exited = process.waitFor(30, TimeUnit.SECONDS);
            if (exited && process.exitValue() == 0) {
                managedProcesses.remove("tomcat");
                return true;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // 如果脚本停止失败，回退到进程终止
        return stopProcess("tomcat");
    }

    // 强制停止进程
    public boolean forceStopProcess(String processName) {
        ProcessInfo info = managedProcesses.get(processName);
        if (info == null) {
            return false;
        }

        try {
            if (isWindows()) {
                Runtime.getRuntime().exec("taskkill /F /PID " + info.getPid());
            } else {
                Runtime.getRuntime().exec("kill -9 " + info.getPid());
            }

            managedProcesses.remove(processName);
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    // 监控进程输出
    private void startOutputMonitoring(Process process, String processName) {
        new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {

                String line;
                while ((line = reader.readLine()) != null) {
                    // 这里可以处理进程输出，比如记录日志或更新UI
                    System.out.println("[" + processName + "] " + line);

                    // 可以发布事件给UI更新
                    EventBus.publish(new ProcessOutputEvent(processName, line));
                }
            } catch (IOException e) {
                // 流关闭，进程可能已结束
            }
        }).start();
    }

    // 监控进程状态
    private void startProcessMonitoring(Process process, String processName) {
        new Thread(() -> {
            try {
                int exitCode = process.waitFor();
                ProcessInfo info = managedProcesses.get(processName);
                if (info != null) {
                    info.setStatus(ProcessStatus.STOPPED);
                    // 发布进程结束事件
                    EventBus.publish(new ProcessTerminatedEvent(processName, exitCode));
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }

    // 获取进程状态
    public ProcessStatus getProcessStatus(String processName) {
        ProcessInfo info = managedProcesses.get(processName);
        if (info == null) {
            return ProcessStatus.UNKNOWN;
        }

        // 检查进程是否还在运行
        if (isProcessRunning(info.getPid())) {
            return ProcessStatus.RUNNING;
        } else {
            info.setStatus(ProcessStatus.STOPPED);
            return ProcessStatus.STOPPED;
        }
    }

    // 检查进程是否运行
    private boolean isProcessRunning(long pid) {
        try {
            if (isWindows()) {
                Process process = Runtime.getRuntime().exec("tasklist /FI \"PID eq " + pid + "\"");
                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(process.getInputStream()))) {

                    String line;
                    while ((line = reader.readLine()) != null) {
                        if (line.contains(String.valueOf(pid))) {
                            return true;
                        }
                    }
                }
            } else {
                Process process = Runtime.getRuntime().exec(new String[]{"ps", "-p", String.valueOf(pid)});
                int exitCode = process.waitFor();
                return exitCode == 0;
            }
        } catch (Exception e) {
            // 忽略异常，认为进程已停止
        }
        return false;
    }

    // 获取进程ID（跨平台）
    private long getProcessId(Process process) {
        try {
            if (process.getClass().getName().equals("java.lang.UNIXProcess")) {
                Field field = process.getClass().getDeclaredField("pid");
                field.setAccessible(true);
                return field.getLong(process);
            }
        } catch (Exception e) {
            // 如果无法获取PID，使用hashCode作为标识
            return System.currentTimeMillis();
        }
        return System.currentTimeMillis();
    }

    private boolean isWindows() {
        return System.getProperty("os.name").toLowerCase().contains("win");
    }

    private boolean waitForProcessTermination(String processName, int timeoutSeconds) {
        long endTime = System.currentTimeMillis() + (timeoutSeconds * 1000);
        while (System.currentTimeMillis() < endTime) {
            if (getProcessStatus(processName) != ProcessStatus.RUNNING) {
                managedProcesses.remove(processName);
                return true;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return false;
            }
        }
        return false;
    }

    // 获取所有管理的进程
    public List<ProcessInfo> getManagedProcesses() {
        return new ArrayList<>(managedProcesses.values());
    }
}
